home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / REVERSEM.ZIP / BOARD.CPP next >
C/C++ Source or Header  |  1994-10-11  |  15KB  |  598 lines

  1. /*--------------------------------------------------------------------------
  2.  
  3.   REVERSEM :
  4.  
  5.   UNIT     : PLAYING BOARD CLASS
  6.  
  7.   COPYRIGHT (C) 1994 Erich P. Gatejen  ALL RIGHTS RESERVED
  8.   This is Freeware.  You may distribute it as you wish.  However, you may not
  9.   distribute a modified version without my consent.
  10.  
  11.   Feel free to cut and paste any algorthm.
  12.  
  13.   NOTE: XTILE is (C) 1992, 1994 by myself.  It is NOT freeware.  You may use
  14.     it for personal projects, but otherwise, it is not to be distributed
  15.     outside this REVERSEM package.  (Contact me if you wish to do
  16.     otherwise)
  17.  
  18. ---------------------------------------------------------------------------*/
  19.  
  20.  
  21. // ------------------------------------------------------------------------
  22. // --- INCLUDES
  23. // ------------------------------------------------------------------------
  24. #include<stdlib.h>
  25. #include<stdio.h>
  26. extern "C" {
  27.    #include "xtile21!.h"
  28. };
  29. #include"string.h"
  30. #include"reversem.hpp"
  31. #include"spots.hpp"
  32. #include"board.hpp"
  33. #include"eval.hpp"
  34.  
  35. // ------------------------------------------------------------------------
  36. // --- PRIVATE MEMBERS
  37. // ------------------------------------------------------------------------
  38.  
  39. // -- Members : Board -----------------------------------------------------
  40.  
  41. BOOLEAN  Board::ValidNorth( void ) {
  42. // The valid checks are brute force.
  43.    register signed int  X = TheGo.XIs();
  44.    register signed int  Y = TheGo.YIs();
  45.  
  46.    // Run north to see if it is a valid move
  47.    Y--;
  48.    // Is is not off the board and is the other player
  49.    if ( Y < TOPY ) return( FALSE );
  50.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  51.  
  52.    Y--;
  53.    while( Y >= TOPY ) {
  54.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE  );
  55.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  56.       Y--;
  57.    };
  58.    return( FALSE );
  59. };
  60.  
  61. void     Board::FlipNorth( void ) {
  62. // The valid checks are brute force.
  63.    register signed int  X = TheGo.XIs();
  64.    register signed int  Y = TheGo.YIs();
  65.  
  66.    // Run north and flip until it is the same player
  67.    Y--;
  68.    while( !Spots[X][Y].IsSpot(Player) ) {
  69.       Spots[X][Y].FlipSpot();
  70.       Y--;
  71.    };
  72. };
  73.  
  74. BOOLEAN  Board::ValidSouth( void ) {
  75. // The valid checks are brute force.
  76.    register signed int  X = TheGo.XIs();
  77.    register signed int  Y = TheGo.YIs();
  78.  
  79.    // Run south to see if it is a valid move
  80.    Y++;
  81.    // Is is not off the board and is the other player
  82.    if ( Y > BOTTOMY ) return( FALSE );
  83.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  84.  
  85.    Y++;
  86.    while( Y <= BOTTOMY ) {
  87.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
  88.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  89.       Y++;
  90.    };
  91.    return( FALSE );
  92. };
  93.  
  94. void     Board::FlipSouth( void ) {
  95. // The valid checks are brute force.
  96.    register signed int  X = TheGo.XIs();
  97.    register signed int  Y = TheGo.YIs();
  98.  
  99.    // Run south to see if it is a valid move
  100.    Y++;
  101.    while( !Spots[X][Y].IsSpot(Player) ) {
  102.      Spots[X][Y].FlipSpot();
  103.      Y++;
  104.    };
  105. };
  106.  
  107. BOOLEAN  Board::ValidWest( void ) {
  108. // The valid checks are brute force.
  109.    register signed int  X = TheGo.XIs();
  110.    register signed int  Y = TheGo.YIs();
  111.  
  112.    // Run north to see if it is a valid move
  113.    X--;
  114.    // Is is not off the board and is the other player
  115.    if ( X < TOPX ) return( FALSE );
  116.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  117.  
  118.    X--;
  119.    while ( X >= TOPX ) {
  120.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE  );
  121.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  122.       X--;
  123.    };
  124.    return( FALSE );
  125. };
  126.  
  127. void     Board::FlipWest( void ) {
  128. // The valid checks are brute force.
  129.    register signed int  X = TheGo.XIs();
  130.    register signed int  Y = TheGo.YIs();
  131.  
  132.    // Run north to see if it is a valid move
  133.    X--;
  134.    while ( !Spots[X][Y].IsSpot(Player) ) {
  135.      Spots[X][Y].FlipSpot();
  136.      X--;
  137.    };
  138. };
  139.  
  140. BOOLEAN  Board::ValidEast( void ) {
  141. // The valid checks are brute force.
  142.    register signed int  X = TheGo.XIs();
  143.    register signed int  Y = TheGo.YIs();
  144.  
  145.    // Run south to see if it is a valid move
  146.    X++;
  147.    // Is is not off the board and is the other player
  148.    if ( X > BOTTOMX ) return( FALSE );
  149.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  150.  
  151.    X++;
  152.    while( X <= BOTTOMX ) {
  153.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
  154.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  155.       X++;
  156.    };
  157.    return( FALSE );
  158. };
  159.  
  160. void     Board::FlipEast( void ) {
  161. // The valid checks are brute force.
  162.    register signed int  X = TheGo.XIs();
  163.    register signed int  Y = TheGo.YIs();
  164.  
  165.    // Run south to see if it is a valid move
  166.    X++;
  167.    while( !Spots[X][Y].IsSpot(Player) ) {
  168.       Spots[X][Y].FlipSpot();
  169.       X++;
  170.    };
  171. };
  172.  
  173. BOOLEAN  Board::ValidNorthEast( void ) {
  174. // The valid checks are brute force.
  175.    register signed int  X = TheGo.XIs();
  176.    register signed int  Y = TheGo.YIs();
  177.  
  178.    // Run north to see if it is a valid move
  179.    Y--;
  180.    X++;
  181.    // Is is not off the board and is the other player
  182.    if ( X > BOTTOMX ) return( FALSE );
  183.    if ( Y < TOPY )    return( FALSE );
  184.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  185.  
  186.    Y--;
  187.    X++;
  188.    while(( Y >= TOPY )&&( X <= BOTTOMX )) {
  189.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE  );
  190.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  191.       Y--;
  192.       X++;
  193.    };
  194.    return( FALSE );
  195. };
  196.  
  197. void     Board::FlipNorthEast( void ) {
  198. // The valid checks are brute force.
  199.    register signed int  X = TheGo.XIs();
  200.    register signed int  Y = TheGo.YIs();
  201.  
  202.    // Run north to see if it is a valid move
  203.    Y--;
  204.    X++;
  205.    while( !Spots[X][Y].IsSpot(Player) ) {
  206.       Spots[X][Y].FlipSpot();
  207.       Y--;
  208.       X++;
  209.    };
  210. };
  211.  
  212. BOOLEAN  Board::ValidNorthWest( void ) {
  213. // The valid checks are brute force.
  214.    register signed int  X = TheGo.XIs();
  215.    register signed int  Y = TheGo.YIs();
  216.  
  217.    // Run north to see if it is a valid move
  218.    X--;
  219.    Y--;
  220.    // Is is not off the board and is the other player
  221.    if ( Y < TOPY ) return( FALSE );
  222.    if ( X < TOPX ) return( FALSE );
  223.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  224.  
  225.    X--;
  226.    Y--;
  227.    while( (Y >= TOPY)&&( X >= TOPX ) ) {
  228.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE  );
  229.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  230.       X--;
  231.       Y--;
  232.    };
  233.    return( FALSE );
  234. };
  235.  
  236. void     Board::FlipNorthWest( void ) {
  237. // The valid checks are brute force.
  238.    register signed int  X = TheGo.XIs();
  239.    register signed int  Y = TheGo.YIs();
  240.  
  241.    // Run north to see if it is a valid move
  242.    X--;
  243.    Y--;
  244.    while( !Spots[X][Y].IsSpot(Player) ) {
  245.       Spots[X][Y].FlipSpot();
  246.       X--;
  247.       Y--;
  248.    };
  249. };
  250.  
  251. BOOLEAN  Board::ValidSouthEast( void ) {
  252. // The valid checks are brute force.
  253.    register signed int  X = TheGo.XIs();
  254.    register signed int  Y = TheGo.YIs();
  255.  
  256.    // Run south to see if it is a valid move
  257.    Y++;
  258.    X++;
  259.    // Is is not off the board and is the other player
  260.    if ( X > BOTTOMX ) return( FALSE );
  261.    if ( Y > BOTTOMY ) return( FALSE );
  262.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  263.  
  264.    Y++;
  265.    X++;
  266.    while( (Y <= BOTTOMY)&&( X <= BOTTOMX ) ) {
  267.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
  268.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  269.       Y++;
  270.       X++;
  271.    };
  272.    return( FALSE );
  273. };
  274.  
  275. void     Board::FlipSouthEast( void ) {
  276. // The valid checks are brute force.
  277.    register signed int  X = TheGo.XIs();
  278.    register signed int  Y = TheGo.YIs();
  279.  
  280.    // Run south to see if it is a valid move
  281.    Y++;
  282.    X++;
  283.    while( !Spots[X][Y].IsSpot(Player) ) {
  284.       Spots[X][Y].FlipSpot();
  285.       Y++;
  286.       X++;
  287.    };
  288. };
  289.  
  290. BOOLEAN  Board::ValidSouthWest( void ) {
  291. // The valid checks are brute force.
  292.    register signed int  X = TheGo.XIs();
  293.    register signed int  Y = TheGo.YIs();
  294.  
  295.    // Run south to see if it is a valid move
  296.    Y++;
  297.    X--;
  298.    // Is is not off the board and is the other player
  299.    if ( Y > BOTTOMY ) return( FALSE );
  300.    if ( X < TOPX ) return( FALSE );
  301.    if ( !(Spots[X][Y].IsOther(Player)) ) return( FALSE );
  302.  
  303.    Y++;
  304.    X--;
  305.    while( (Y <= BOTTOMY)&&(X >= TOPX ) ) {
  306.       if ( Spots[X][Y].IsSpot(Player) ) return( TRUE );
  307.       if ( Spots[X][Y].IsSpotBlank()  ) return( FALSE );
  308.       Y++;
  309.       X--;
  310.    };
  311.    return( FALSE );
  312. };
  313.  
  314. void    Board::FlipSouthWest( void ) {
  315. // The valid checks are brute force.
  316.    register signed int  X = TheGo.XIs();
  317.    register signed int  Y = TheGo.YIs();
  318.  
  319.    // Run south to see if it is a valid move
  320.    Y++;
  321.    X--;
  322.    while( !Spots[X][Y].IsSpot(Player) ) {
  323.       Spots[X][Y].FlipSpot();
  324.       Y++;
  325.       X--;
  326.    };
  327. };
  328.  
  329. // ------------------------------------------------------------------------
  330. // --- PUBLIC MEMBERS
  331. // ------------------------------------------------------------------------
  332.  
  333. Board::Board( Board *OldBoard ) {
  334.  
  335.    memcpy( Spots, OldBoard->Spots, sizeof( Spots ) );
  336.  
  337. };
  338.  
  339. Board::Board( Spot  TheSpots[BOARDXSIZE][BOARDYSIZE] ) {
  340.  
  341.    memcpy( Spots, TheSpots, sizeof( Spots ) );
  342.  
  343. };
  344.  
  345. void  Board::InitBoard2Start( void ) {
  346.  
  347.    register int X, Y;
  348.  
  349.    for ( X = 0; X < BOARDXSIZE; X++ ) {
  350.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  351.  
  352.      Spots[X][Y].Is( SPOT_BLANK );
  353.       }
  354.    }
  355.  
  356.    Spots[3][3].Is( SPOT_WHITE );
  357.    Spots[3][4].Is( SPOT_BLACK );
  358.    Spots[4][3].Is( SPOT_BLACK );
  359.    Spots[4][4].Is( SPOT_WHITE );
  360.  
  361.  
  362. };
  363.  
  364.  
  365. BOOLEAN  Board::ValidGo( Go  GoTo, SpotStates  ThePlayer ) {
  366.  
  367.    // If a piece is already there, it is not valid.
  368.    if ( !Spots[GoTo.XIs()][GoTo.YIs()].IsSpotBlank() ) return FALSE;
  369.  
  370.    // Copy to local
  371.    TheGo  = GoTo;
  372.    Player = ThePlayer;
  373.  
  374.    // Walk in compass directions; if any are valid, the go is valid
  375.    if (ValidNorth()) return (TRUE);
  376.    if (ValidSouth()) return (TRUE);
  377.    if (ValidEast ()) return (TRUE);
  378.    if (ValidWest ()) return (TRUE);
  379.    if (ValidNorthEast()) return (TRUE);
  380.    if (ValidNorthWest()) return (TRUE);
  381.    if (ValidSouthEast()) return (TRUE);
  382.    if (ValidSouthWest()) return (TRUE);
  383.    return( FALSE );
  384.  
  385. };
  386.  
  387.  
  388. void  Board::DoGo ( Go  GoTo, SpotStates  ThePlayer  ) {
  389.  
  390.    // Copy the go local
  391.    TheGo  = GoTo;
  392.    Player = ThePlayer;
  393.  
  394.    // Do the go, flip as appropriate, for each compass direction
  395.    Spots[TheGo.XIs()][TheGo.YIs()].Is( Player );
  396.  
  397.    if (ValidNorth())     FlipNorth();
  398.    if (ValidSouth())     FlipSouth();
  399.    if (ValidEast ())     FlipEast ();
  400.    if (ValidWest ())     FlipWest ();
  401.    if (ValidNorthEast())  FlipNorthEast ();
  402.    if (ValidNorthWest())  FlipNorthWest ();
  403.    if (ValidSouthEast())  FlipSouthEast ();
  404.    if (ValidSouthWest())  FlipSouthWest ();
  405.  
  406. };
  407.  
  408.  
  409. heuristic Board::Evaluate( SpotStates  ThePlayer ) {
  410.  
  411.    heuristic    Value = 0;
  412.    int        X;
  413.    int          Y;
  414.  
  415.    // Copy the go local
  416.    Player = ThePlayer;
  417.  
  418.    // We need to evaluate the heuristic merit of this board for Player
  419.    // This is where playing with this code will give you the biggest
  420.    // pay off
  421.  
  422.    // OK, do the evals that require a visit to every spot
  423.    for ( X = 0;  X < BOARDXSIZE; X++ ) {
  424.  
  425.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  426.  
  427.      // Use a case to do some of the evals for some of the levels
  428.      switch( BrainLevel ) {
  429.  
  430.         case EXPERIMENTAL:
  431.            // Through in a random modifier.
  432.            Value += (random( 5000 ) - 2500);
  433.  
  434.         case GENIUS:
  435.         case SWIFT:
  436.            // Apply the opponate value
  437.            if ( Spots[X][Y].IsOther( Player ) )
  438.           Value += OpponantVal[X][Y];
  439.  
  440.         case AVERAGE:
  441.            // Apply the player value
  442.            if ( Spots[X][Y].IsSpot( Player ) )
  443.           Value += PlayerVal[X][Y];
  444.  
  445.         case DULLARD:
  446.  
  447.            // Count bad guys spots
  448.            if ( Spots[X][Y].IsOther( Player ) )
  449.           Value -= SPOT_VALUE;
  450.  
  451.         case SIMPLETON:
  452.  
  453.            // Count good guys spots
  454.            if ( Spots[X][Y].IsSpot( Player ) )
  455.           Value += SPOT_VALUE;
  456.            break;
  457.  
  458.  
  459.      } // end case
  460.  
  461.       } // end inner for
  462.    }
  463.  
  464.    // Do multipliers for brain level.  This will spread out the H
  465.    switch( BrainLevel ) {
  466.  
  467.       case AVERAGE:  Value = Value * 2;
  468.              break;
  469.  
  470.       case DULLARD:  Value = Value * 3;
  471.              break;
  472.  
  473.       case SIMPLETON: Value = Value * 4;
  474.               break;
  475.  
  476.    }
  477.  
  478.    return Value;
  479. };
  480.  
  481. heuristic Board::WinOrLose(  SpotStates  ThePlayer  ) {
  482.  
  483.    int        X;
  484.    int          Y;
  485.    int         GoodGuys  = 0;
  486.    int        BadGuys   = 0;
  487.  
  488.    // Copy the go local
  489.    Player = ThePlayer;
  490.  
  491.    // Count up the spots.
  492.    for ( X = 0;  X < BOARDXSIZE; X++ ) {
  493.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  494.  
  495.      if ( Spots[X][Y].IsSpot( Player ) )
  496.         GoodGuys++;
  497.  
  498.      else  if ( Spots[X][Y].IsOther( Player ) )
  499.         BadGuys++;
  500.  
  501.       } // end inner for
  502.    }
  503.  
  504.    // Is it a tie, win, or loss.
  505.    if ( GoodGuys == BadGuys )
  506.       return( 0 );
  507.  
  508.    else if ( GoodGuys > BadGuys )
  509.       return( VERY_GOOD_THING );
  510.  
  511.    else
  512.       return( VERY_BAD_THING  );
  513.  
  514. };
  515.  
  516. int  Board::Count( SpotStates  ThePlayer  ) {
  517.  
  518.    int        X;
  519.    int          Y;
  520.    int         Count  = 0;
  521.  
  522.    // Copy the go local
  523.    Player = ThePlayer;
  524.  
  525.    // Count up the spots.
  526.    for ( X = 0;  X < BOARDXSIZE; X++ ) {
  527.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  528.  
  529.      if ( Spots[X][Y].IsSpot( Player ) )
  530.         Count++;
  531.  
  532.      else  if ( Spots[X][Y].IsOther( Player ) )
  533.         Count--;
  534.  
  535.       } // end inner for
  536.    }
  537.  
  538.    return( Count );
  539.  
  540. };
  541.  
  542.  
  543. BOOLEAN   Board::MoveExists( SpotStates  ThePlayer ) {
  544.  
  545.    register int        X;
  546.    register int         Y;
  547.    Go            AGo;
  548.  
  549.    // OK, do the evals that require a visit to every spot
  550.    for ( X = 0;  X < BOARDXSIZE; X++ ) {
  551.  
  552.       for ( Y = 0; Y < BOARDYSIZE; Y++ ) {
  553.  
  554.      AGo.XIs(X);
  555.      AGo.YIs(Y);
  556.  
  557.      if ( ValidGo( AGo, ThePlayer ) ) return TRUE;
  558.  
  559.       } // end inner for
  560.    }
  561.  
  562.    return FALSE;
  563.  
  564. };
  565.  
  566.  
  567. // OK!!  Board has a couple of static members.  Lets define them.
  568.    SpotStates   Board::Player;
  569.    BRAIN    Board::BrainLevel;
  570.    Go        Board::TheGo;
  571.  
  572.  
  573.    // The following are the evaluation boards.  They are col major (sorry)
  574.    int      Board::PlayerVal[BOARDXSIZE][BOARDYSIZE] = {
  575.  
  576.       { 900,  -220,  90, 70, 70,  90, -220, 900 },
  577.       { -220, -200, -20, 0,  0,  -20, -200, -220 },
  578.       {  90,  -30,   30, 40, 20,  40, -30,  90  },
  579.       {  78,   0,    40, 0,  0,   20,  0,   78  },
  580.       {  78,   0,    20, 0,  0,   40,  0,   78  },
  581.       {  90,  -30,   40, 20, 40,  30, -30,  90  },
  582.       { -220, -200, -20, 0,  0,  -20, -200, -220 },
  583.       { 900,  -220,  90, 70, 70,  90, -220, 900 }
  584.    };
  585.  
  586.    int    Board::OpponantVal[BOARDXSIZE][BOARDYSIZE] = {
  587.  
  588.       { -2000,  90, -20, -15, -15, -20, 90, -2000 },
  589.       {   80, 200,  10,  30,  30,  10, 100,  90  },
  590.       {  -20,  10,  0,   0,   0,   0,  10,  -20  },
  591.       {  -15,  30,  0,   0,   0,   0,  30,  -15  },
  592.       {  -15,  30,  0,   0,   0,   0,  30,  -15  },
  593.       {  -20,  10,  0,   0,   0,   0,  10,  -20  },
  594.       {   80, 200,  10,  30,  30,  10, 100,  90  },
  595.       { -2000,  90, -20, -15, -15, -20, 90, -2000 },
  596.  
  597.    };
  598.